﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.AccessControl;

namespace SaveAvailableData
{
    public static class CSource
    {
        public static Dictionary<long, long> _lIndexDir = new Dictionary<long, long>(1024 * 1024);

        public static string strDirPath = "D:\\";

        public static Queue<Queue<double[]>> _queWavSource = new Queue<Queue<double[]>>(40 * 1024 * 1024);

        //光谱高斯处理后台解析
        public static string strTmpPath = string.Empty;
        public static Queue<long> wavQIndex = new Queue<long>(7200);

        public static long lCount = 0;

        //当前文件名
        public static string strCurPath = string.Empty;

        
        #region //查找存在的文件
        public static void GetLatestFileList0(string strDir, ref Queue<String> lstFile, string strFileType = "*.*")
        {
            GetLatestFileList(strDir, ref lstFile);
            if ((strFileType == string.Empty || strFileType.Trim() == "*.*") || lstFile.Count == 0)
            {
                return;
            }
            string[] strArray = (string[])lstFile.ToArray().Clone();
            lstFile.Clear();
            string _strType = strFileType.Trim().ToLower();
            foreach (string str in strArray)
            {
                string[] strTmp = str.Trim().ToLower().Split('.');
                if (strTmp[strTmp.Length - 1] == _strType)
                {
                    lstFile.Enqueue(str);
                }
            }
        }

        public static void GetLatestFileList(string strDir, ref Queue<String> lstFile, string strFileType="*.*")
        {
            //查找指定类型的文件
            bool bFindFileType = false;
            string strType="*";
            if (strFileType != string.Empty && strFileType.Trim() !=string.Format("*.*"))
            {
                string[] strTypeArray = strFileType.Trim().ToLower().Split('.');
                strType = strTypeArray[strTypeArray.Length - 1];
                bFindFileType = true;
            }
            
            if (lstFile.Count < 1)
            {
                lstFile = new Queue<string>();
            }

            if (!Directory.Exists(strDir))
            {
                return;
            }

            try
            {
                DirectoryInfo dif = new DirectoryInfo(strDir);
                FileInfo[] fis = dif.GetFiles();
                foreach (FileInfo fi in fis)
                {
                    if (!lstFile.Contains(fi.FullName))
                    {
                        if (bFindFileType)
                        {
                            string[] strTmp = fi.FullName.Trim().ToLower().Split('.');
                            if (strTmp[strTmp.Length - 1] != strType)
                            {
                                continue;
                            } 
                        }
                        lstFile.Enqueue(fi.FullName);
                    }
                }

                DirectoryInfo[] difs = dif.GetDirectories();

                foreach (DirectoryInfo _dif in difs)
                {
                    if (FileAttributes.Directory == _dif.Attributes)
                    {
                        GetLatestFileList(_dif.FullName, ref lstFile,strFileType);
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.StackTrace + ":" + ex.Message);
            }
        }

        public static void GetLatestFileList( string strDir,ref Queue<String> lstFile)
        {
            if (lstFile.Count<1)
            {
                lstFile = new Queue<string>();
            }
            if (!Directory.Exists(strDir))
            {
                return;
            }
            try
            {
                DirectoryInfo dif=new DirectoryInfo (strDir);
                FileInfo[] fis = dif.GetFiles();
                foreach (FileInfo fi in fis)
                {
                    if (!lstFile.Contains(fi.FullName))
                    {
                        lstFile.Enqueue(fi.FullName);
                    }
                }
                
                DirectoryInfo[] difs = dif.GetDirectories();
                
                foreach (DirectoryInfo _dif in difs)
                {
                    if (FileAttributes.Directory == _dif.Attributes)
                    {
                        GetLatestFileList(_dif.FullName, ref lstFile);
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.StackTrace+":"+ex.Message);
            }
        }
        #endregion

        #region//获取波长值
        private static double A = 1570.398804;
        private static double B1 = -0.1617357432842254600000000;
        private static double B2 = -0.0000663390237605199220000;
        private static double B3 = -0.0000000354414062542218740;
        private static double B4 = 0.0000000001906033247900396;
        private static double B5 = -0.0000000000003401445791695;
        private static double[] PreWav = new double[32];

        public static void GetWavesLength(double[] Spectra, ref double[] wavelength)
        {
            int fbgNo = 0;
            GetWavesLength(Spectra, ref wavelength, ref fbgNo);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Spectra"></param>
        /// <param name="wavelength"></param>
        /// <param name="fbgNo"></param>
        public static void GetWavesLength(double[] Spectra, ref double[] wavelength, ref int fbgNo)
        {
            List<double> lstwav = new List<double>();
            fbgNo = 0;
            int iCount = 0;
            double[] _x = new double[256], _y = new double[256];
            for (int i = 0; i < Spectra.Length; i++)
            {
                if (Spectra[i] > 0)
                {
                    _x[iCount] = i;
                    _y[iCount++] = Math.Pow(Spectra[i], 2);
                }
                else if (iCount > 0)
                {
                    if (iCount > 2)
                    {
                        double[] _tx = new double[iCount];
                        double[] _ty = new double[iCount];
                        while (iCount-- > 0)
                        {
                            _tx[iCount] = _x[iCount];
                            _ty[iCount] = _y[iCount];
                        }
                        //PreWav[fbgNo] = _wavlen(_tx, _ty);
                        PreWav[fbgNo] = (PreWav[fbgNo] > 0) ? Avrdouble(PreWav[fbgNo], _wavlen(_tx, _ty)) : _wavlen(_tx, _ty);
                        if (PreWav[fbgNo] < 1525 || PreWav[fbgNo] > 1570)
                        {
                            continue;
                        }
                        lstwav.Add(Math.Round(PreWav[fbgNo++], 5));
                    }
                    _x = new double[256];
                    _y = new double[256];
                    iCount = 0;
                }
            }
            lstwav.Sort();
            wavelength = lstwav.ToArray();
        }
        private static double Avrdouble(double _dpre, double _d)
        {
            double _t = Math.Abs(Math.Floor((_d - _dpre) * 1000d));
            if (_t < 180) return _d;
            if (_t < 250) return _dpre;
            return 0.25d * _d + 0.75d * _dpre;
        }

        /// <summary>
        /// 通过高斯拟合（最小二乘法求参数）求出波长值
        /// </summary>
        /// <param name="_X">因子</param>
        /// <param name="_Y">因子</param>
        /// <returns>波长值</returns>
        private static double _wavlen(double[] _X, double[] _Y)
        {
            if (_X.Length != _Y.Length || _Y.Length < 3)
            {
                return 0;
            }
            try
            {
                double s00 = 0, s10 = 0, s20 = 0, s30 = 0, s40 = 0, s01 = 0, s11 = 0, s21 = 0;
                for (int i = 0; i < _X.Length; i++)
                {
                    s00 += 1;//sigma x^0*y^0;
                    s10 += _X[i];//sigma x;   
                    s20 += Math.Pow(_X[i], 2);//sigma x^2;
                    s30 += Math.Pow(_X[i], 3);//sigma x^3;
                    s40 += Math.Pow(_X[i], 4);//sigma x^4
                    s01 += _Y[i]; //sigma y;
                    s11 += _X[i] * _Y[i]; //sigma x*y;
                    s21 += _X[i] * _X[i] * _Y[i];//sigma x^2*y;
                }
                double tmp = 0.5d * (s21 * (s20 * s10 - s30 * s00) + s11 * (s40 * s00 - s20 * s20) + s01 * (s30 * s20 - s40 * s10))
                            /
                            (s21 * (s10 * s10 - s20 * s00) + s11 * (s30 * s00 - s20 * s10) + s01 * (s20 * s20 - s30 * s10));

                return (A + B1 * tmp + B2 * Math.Pow(tmp, 2) + B3 * Math.Pow(tmp, 3) + B4 * Math.Pow(tmp, 4) + B5 * Math.Pow(tmp, 5));
            }
            catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.StackTrace + ":" + ex.Message); }
            return 0;
        }
        #endregion
    }

    /// <summary>
    /// 均值滤波
    /// </summary>
    public class FilterAvg
    {
        private double[] dValues = null;
        private int iCount = 0;
        private int iLen = 0;
        private double _dValue = 0;

        public FilterAvg(int iAvgCount)
        {
            iCount = iAvgCount;
            dValues = new double[iCount];
            iLen = 0;
            _dValue = 0;
        }
        public double AppendValue(double V)
        {
            double ret = 0;
            if (iLen < iCount) iLen++;
            for (int i = dValues.Length - iLen; i < dValues.Length - 1; i++)
            {
                dValues[i] = dValues[i + 1];
                ret += dValues[i];
            }
            dValues[dValues.Length - 1] = V;
            _dValue = (ret + V) / iLen;
            return _dValue;
        }

        public void Reset()
        {
            iLen = 0;
            _dValue = 0;
        }
        public double dValue
        {
            get { return _dValue; }
        }
    }
    /// <summary>
    /// 带通滤波
    /// </summary>
    public class FilterWidth
    {
        private double dWidth = 0;
        private double dMin = 0;
        private double dMax = 0;
        private bool bHadValue = false;
        private double _dValue = 0;

        public FilterWidth(double dFilterWidth)
        {
            dWidth = dFilterWidth;
            dMin = 0;
            dMax = 0;
            bHadValue = false;
        }
        public double AppendValue(double V)
        {
            if (bHadValue)
            {
                if (V < dMin)
                {
                    if (dMax - V > dWidth)
                    {
                        dMax = dMin;
                        dMin = V;
                    }
                }
                else
                {
                    if (V > dMax)
                    {
                        if (V - dMin > dWidth)
                        {
                            dMin = dMax;
                            dMax = V;
                        }
                    }
                }
            }
            else
            {
                dMin = V;
                dMax = V;
                bHadValue = true;
            }

            _dValue = (dMax + dMin) / 2;
            return _dValue;
        }
        public void Reset()
        {
            dMin = 0;
            dMax = 0;
            bHadValue = false;
        }
        public double dValue
        {
            get { return _dValue; }
        }
    }
    /// <summary>
    /// 寻峰算法
    /// </summary>
    public class FinderMax
    {
        enum Status { stUp, stDown, stNone }
        private int _iCount = 0;
        private double dLastValue = 0;
        private bool bHadValue = false;
        private double V1 = 0, V2 = 0, V3 = 0;
        private double dSeed = 0;

        private Status _status = Status.stNone;

        public FinderMax(double Seed)
        {
            dSeed = Seed;
            _status = Status.stNone;
            dLastValue = 0;
            _iCount = 0;
            V1 = 0;
            V2 = 0;
            V3 = 0;
        }

        public bool AppendValue(double V)
        {
            Boolean ret = false;

            if (bHadValue)
            {
                if (V != dLastValue)
                {
                    switch (_status)
                    {
                        case Status.stUp:
                            {
                                if (V > dLastValue)
                                {
                                    V2 = V;
                                    V3 = V;
                                }
                                else
                                {
                                    V3 = V;
                                    if (V2 - V1 > dSeed) { _status = Status.stDown; } else { _status = Status.stNone; }
                                }
                                break;
                            }
                        case Status.stDown:
                            {
                                if (V < dLastValue) { V3 = V; } else { _status = Status.stNone; }
                                if (V2 - V3 > dSeed)
                                {
                                    ret = true;
                                    _iCount++;
                                    _status = Status.stNone;
                                }
                                break;
                            }
                        default:
                            {
                                if (V > dLastValue)
                                {
                                    V1 = V;
                                    V2 = V;
                                    V3 = V;
                                    _status = Status.stUp;
                                }
                                break;
                            }
                    }
                    dLastValue = V;
                }
            }
            else { bHadValue = true; }

            return ret;
        }
        public void Reset()
        {
            _status = Status.stNone;
            dLastValue = 0;
            _iCount = 0;
            V1 = 0;
            V2 = 0;
            V3 = 0;
        }
        public int iCount
        {
            get { return _iCount; }
        }
    }
}